package com.md.livingwidget.dialog.internal;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.ScrollView;

import com.md.basedpc.PHSizeUtils;
import com.md.livingwidget.R;
import com.md.livingwidget.dialog.GravityEnum;
import com.md.livingwidget.dialog.StackingBehavior;
import com.md.livingwidget.uiutils.ShapeUtils;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;

/**
 * 处理：titleFrame（md_stub_titleFrame）内容（文本、自定义视图、列表视图，
 *
 * @author wanggq
 * @date :2019-11-25 17:46
 */
public class DLRootLayout extends ViewGroup {

    private static final int INDEX_NEUTRAL = 0;
    private static final int INDEX_NEGATIVE = 1;
    private static final int INDEX_POSITIVE = 2;
    private final DLButton[] buttons = new DLButton[3];
    private int maxHeight;
    private View titleBar;
    private View content;
    private CheckBox checkPrompt;
    private boolean drawTopDivider = false;
    private boolean drawBottomDivider = false;
    private StackingBehavior stackBehavior = StackingBehavior.ADAPTIVE;
    private boolean isStacked = false;
    private boolean useFullPadding = true;
    private boolean reducePaddingNoTitleNoButtons;
    private boolean noTitleNoPadding;

    private int noTitlePaddingFull;
    private int buttonPaddingFull;
    private int buttonBarHeight;
    private float btnRadius;
    private GravityEnum buttonGravity = GravityEnum.START;

    /* Margin from dialog frame to first button */
    private int buttonHorizontalEdgeMargin;

    //    private Paint dividerPaint;
    View md_buttontop_line;
    View md_buttontop_line1;
    View md_buttontop_line2;

    View md_leftdiver_line;
    View md_rightdiver_line;

    private ViewTreeObserver.OnScrollChangedListener topOnScrollChangedListener;
    private ViewTreeObserver.OnScrollChangedListener bottomOnScrollChangedListener;
    private int dividerWidth;

    public DLRootLayout(Context context) {
        super(context);
        init(context, null, 0);
    }

    public DLRootLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public DLRootLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public DLRootLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs, defStyleAttr);
    }

    private static boolean isVisible(@Nullable View v) {
        boolean visible = v != null && v.getVisibility() != View.GONE;
        if (visible && v instanceof DLButton) {
            visible = ((DLButton) v).getText().toString().trim().length() > 0;
        }
        return visible;
    }

    public static boolean canRecyclerViewScroll(@Nullable RecyclerView view) {
        return view != null
                && view.getLayoutManager() != null
                && view.getLayoutManager().canScrollVertically();
    }

    private static boolean canScrollViewScroll(ScrollView sv) {
        if (sv.getChildCount() == 0) {
            return false;
        }
        final int childHeight = sv.getChildAt(0).getMeasuredHeight();
        return sv.getMeasuredHeight() - sv.getPaddingTop() - sv.getPaddingBottom() < childHeight;
    }

    private static boolean canWebViewScroll(WebView view) {
        //noinspection deprecation
        return view.getMeasuredHeight() < view.getContentHeight() * view.getScale();
    }

    private static boolean canAdapterViewScroll(AdapterView lv) {
        /* Force it to layout it's children */
        if (lv.getLastVisiblePosition() == -1) {
            return false;
        }

        /* We can scroll if the first or last item is not visible */
        boolean firstItemVisible = lv.getFirstVisiblePosition() == 0;
        boolean lastItemVisible = lv.getLastVisiblePosition() == lv.getCount() - 1;

        if (firstItemVisible && lastItemVisible && lv.getChildCount() > 0) {
            /* Or the first item's top is above or own top */
            if (lv.getChildAt(0).getTop() < lv.getPaddingTop()) {
                return true;
            }
            /* or the last item's bottom is beyond our own bottom */
            return lv.getChildAt(lv.getChildCount() - 1).getBottom()
                    > lv.getHeight() - lv.getPaddingBottom();
        }

        return true;
    }

    /**
     * Find the view touching the bottom of this ViewGroup. Non visible children are ignored, however
     * getChildDrawingOrder is not taking into account for simplicity and because it behaves
     * inconsistently across platform versions.
     *
     * @return View touching the bottom of this ViewGroup or null
     */
    @Nullable
    private static View getBottomView(@Nullable ViewGroup viewGroup) {
        if (viewGroup == null || viewGroup.getChildCount() == 0) {
            return null;
        }
        View bottomView = null;
        for (int i = viewGroup.getChildCount() - 1; i >= 0; i--) {
            View child = viewGroup.getChildAt(i);
            if (child.getVisibility() == View.VISIBLE
                    && child.getBottom() == viewGroup.getMeasuredHeight()) {
                bottomView = child;
                break;
            }
        }
        return bottomView;
    }

    @Nullable
    private static View getTopView(@Nullable ViewGroup viewGroup) {
        if (viewGroup == null || viewGroup.getChildCount() == 0) {
            return null;
        }
        View topView = null;
        for (int i = viewGroup.getChildCount() - 1; i >= 0; i--) {
            View child = viewGroup.getChildAt(i);
            if (child.getVisibility() == View.VISIBLE && child.getTop() == 0) {
                topView = child;
                break;
            }
        }
        return topView;
    }

    private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        noTitlePaddingFull = PHSizeUtils.dp2px(context, 16);
        buttonPaddingFull = PHSizeUtils.dp2px(context, 8);
        buttonHorizontalEdgeMargin = PHSizeUtils.dp2px(context, 8);
        buttonBarHeight = PHSizeUtils.dp2px(context, 48);
        dividerWidth = PHSizeUtils.dp2px(context, 0.5f);
        btnRadius = getContext().getResources().getDimension(R.dimen.md_bg_corner_radius);

        setWillNotDraw(false);
    }

    public void setMaxHeight(int maxHeight) {
        this.maxHeight = maxHeight;
    }

    public void noTitleNoPadding() {
        noTitleNoPadding = true;
    }

    @Override
    public void onFinishInflate() {
        super.onFinishInflate();
        for (int i = 0; i < getChildCount(); i++) {
            View v = getChildAt(i);
            if (v.getId() == R.id.md_titleFrame) {
                titleBar = v;
            }
            // 分割线 ，动态计算 仿IOS标准按钮
            else if (v.getId() == R.id.md_buttontop_line) {
                md_buttontop_line = v;
            } else if (v.getId() == R.id.md_buttontop_line1) {
                md_buttontop_line1 = v;
            } else if (v.getId() == R.id.md_buttontop_line2) {
                md_buttontop_line2 = v;
            } else if (v.getId() == R.id.md_leftdiver_line) {
                md_leftdiver_line = v;
            } else if (v.getId() == R.id.md_rightdiver_line) {
                md_rightdiver_line = v;
            }
            // button
            else if (v.getId() == R.id.md_buttonDefaultNeutral) {
                buttons[INDEX_NEUTRAL] = (DLButton) v;
            } else if (v.getId() == R.id.md_buttonDefaultNegative) {
                buttons[INDEX_NEGATIVE] = (DLButton) v;
            } else if (v.getId() == R.id.md_buttonDefaultPositive) {
                buttons[INDEX_POSITIVE] = (DLButton) v;
            } else if (v.getId() == R.id.md_promptCheckbox) {
                checkPrompt = (CheckBox) v;
            } else {
                content = v;
            }
        }
    }

    boolean hasButtons = false;

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        if (height > maxHeight) {
            height = maxHeight;
        }

        useFullPadding = true;

        final boolean stacked;
        if (stackBehavior == StackingBehavior.ALWAYS) {
            stacked = true;
        } else if (stackBehavior == StackingBehavior.NEVER) {
            stacked = false;
        } else {
            int buttonsWidth = 0;
            for (DLButton button : buttons) {
                if (button != null && isVisible(button)) {
                    button.setStacked(false, false);
                    measureChild(button, widthMeasureSpec, heightMeasureSpec);
                    buttonsWidth += button.getMeasuredWidth();
                    hasButtons = true;
                }
            }
//            int buttonBarPadding = getContext().getResources().getDimensionPixelSize(R.dimen.md_neutral_button_margin);
            int buttonBarPadding = buttonPaddingFull;
            final int buttonFrameWidth = width - 2 * buttonBarPadding;
            stacked = buttonsWidth > buttonFrameWidth;
        }

        int stackedHeight = 0;
        isStacked = stacked;
        if (stacked) {
            for (DLButton button : buttons) {
                if (button != null && isVisible(button)) {
                    button.setStacked(true, false);
                    measureChild(button, widthMeasureSpec, heightMeasureSpec);
                    stackedHeight += button.getMeasuredHeight();
                    hasButtons = true;
                }
            }
        }

        int availableHeight = height;
        int fullPadding = 0;
        int minPadding = 0;
        if (hasButtons) {
            if (isStacked) {
                availableHeight -= stackedHeight;
                fullPadding += 2 * buttonPaddingFull;
                minPadding += 2 * buttonPaddingFull;
            } else {
                availableHeight -= buttonBarHeight;
                fullPadding += 2 * buttonPaddingFull;
                /* No minPadding */
            }
        } else {
            /* Content has 8dp, we add 16dp and get 24dp, the frame margin */
            fullPadding += 2 * buttonPaddingFull;
        }

        if (isVisible(titleBar)) {
            titleBar.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED);
            availableHeight -= titleBar.getMeasuredHeight();
        } else if (!noTitleNoPadding) {
            fullPadding += noTitlePaddingFull;
        }
        if (isVisible(content)) {
            content.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(availableHeight - minPadding, MeasureSpec.AT_MOST));
            if (content.getMeasuredHeight() <= availableHeight - fullPadding) {
                if (!reducePaddingNoTitleNoButtons || isVisible(titleBar) || hasButtons) {
                    useFullPadding = true;
                    availableHeight -= content.getMeasuredHeight() + fullPadding;
                } else {
                    useFullPadding = false;
                    availableHeight -= content.getMeasuredHeight() + minPadding;
                }
            } else {
                useFullPadding = false;
                availableHeight = 0;
            }
        }
        setMeasuredDimension(width, height - availableHeight);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    int topImageviewHeight;

    public void setTopImageHeight(int topImageviewHeight) {
        this.topImageviewHeight = topImageviewHeight;
        requestLayout();
    }

    /***
     * button 按钮重新绘制 定位置
     * @param changed
     * @param l
     * @param t
     * @param r
     * @param b
     * onLayout(boolean changed, int left, int top, int right, int bottom)
     */
    @Override
    protected void onLayout(boolean changed, final int l, int t, final int r, int b) {
        t -= topImageviewHeight;
        b -= topImageviewHeight;

        if (isVisible(titleBar)) {
            int height = titleBar.getMeasuredHeight();
            titleBar.layout(l, t, r, t + height);
            t += height;
        } else if (!noTitleNoPadding && useFullPadding) {
            t += noTitlePaddingFull;
        }

        if (isVisible(content)) {
            content.layout(l, t, r, t + content.getMeasuredHeight());
            t += content.getMeasuredHeight();
        }
        if (isStacked) {
            b -= buttonPaddingFull;
            int i = 0;
            for (DLButton mButton : buttons) {
                if (isVisible(mButton)) {
                    mButton.layout(l, b - mButton.getMeasuredHeight(), r, b);
                    b -= mButton.getMeasuredHeight();
                    // 支持三个垂直按钮
                    if (i == 0) {
                        md_buttontop_line.layout(l, b, r, b + 1);
                    } else if (i == 1) {
                        md_buttontop_line1.layout(l, b, r, b + 1);
                    } else if (i == 2) {
                        md_buttontop_line2.layout(l, b, r, b + 1);
                    }
                    i++;
                }
            }

        } else {   // 水平方向排列
            int barTop;
            int barBottom = b;
            barTop = barBottom - buttonBarHeight;
            Log.e("MDRootLayout", "barTop: " + barTop);
            Log.e("MDRootLayout", "t: " + t);
            Log.e("topImageviewHeight", "topImageviewHeight: " + topImageviewHeight);
            if (hasButtons) {
                int neutralLeft = l;
                int buttonShowCount = 0;

                boolean isShowFirst = isVisible(buttons[INDEX_POSITIVE]);
                boolean isShowSecond = isVisible(buttons[INDEX_NEGATIVE]);
                boolean isShowThird = isVisible(buttons[INDEX_NEUTRAL]);
                if (isShowFirst) buttonShowCount++;
                if (isShowSecond) buttonShowCount++;
                if (isShowThird) buttonShowCount++;

                List<DLButton> buttonList = new ArrayList<>();
                int width = (int) (getMeasuredWidth() * 1f / buttonShowCount);
                if (isShowFirst) {
                    neutralLeft = l;
                    buttons[INDEX_POSITIVE].layout(neutralLeft, barTop, neutralLeft + width, barBottom);
                    neutralLeft += width;
                    buttonList.add(buttons[INDEX_POSITIVE]);
                }

                if (isShowSecond) {
                    buttons[INDEX_NEGATIVE].layout(neutralLeft, barTop, neutralLeft + width, barBottom);
                    neutralLeft += width;
                    buttonList.add(buttons[INDEX_NEGATIVE]);
                }

                if (isShowThird) {
                    buttons[INDEX_NEUTRAL].layout(neutralLeft, barTop, neutralLeft + width, barBottom);
                    buttonList.add(buttons[INDEX_NEUTRAL]);
                }
                int btnFillColor = btnBgColor;
                if (buttonList.size() == 1) {
                    buttonList.get(0).setBackgroundDrawable(ShapeUtils.getDrawableList(0, 0, 0, btnRadius, btnRadius, 0, btnFillColor));
                } else if (buttonList.size() == 2) {
                    buttonList.get(0).setBackgroundDrawable(ShapeUtils.getDrawableList(0, 0, 0, 0, btnRadius, 0, btnFillColor));
                    buttonList.get(1).setBackgroundDrawable(ShapeUtils.getDrawableList(0, 0, 0, btnRadius, 0, 0, btnFillColor));
                } else if (buttonList.size() == 3) {
                    buttonList.get(0).setBackgroundDrawable(ShapeUtils.getDrawableList(0, 0, 0, 0, btnRadius, 0, btnFillColor));
                    buttonList.get(1).setBackgroundDrawable(ShapeUtils.getDrawableList(0, 0, 0, 0, 0, 0, btnFillColor));
                    buttonList.get(2).setBackgroundDrawable(ShapeUtils.getDrawableList(0, 0, 0, btnRadius, 0, 0, btnFillColor));
                }
                /**
                 * View md_buttontop_line;
                 * View md_leftdiver_line;
                 * View md_rightdiver_line;
                 */
                int lineWidth = 1;
                md_buttontop_line.layout(l, barTop, r, barTop + lineWidth);
                if (buttonShowCount == 2) {
                    md_leftdiver_line.layout(l + (buttonShowCount - 1) * width, barTop, l + width + lineWidth, barBottom);
                } else if (buttonShowCount == 3) {
                    md_leftdiver_line.layout(l + (buttonShowCount - 2) * width, barTop, (buttonShowCount - 2) * width + lineWidth, barBottom);
                    md_rightdiver_line.layout(l + (buttonShowCount - 1) * width, barTop, (buttonShowCount - 1) * width + lineWidth, barBottom);
                }
            }
        }

        setUpDividersVisibility(content, true, true);
    }


    public void setStackingBehavior(StackingBehavior behavior) {
        stackBehavior = behavior;
        invalidate();
    }

    public void setDividerColor(int dividerColor) {
        md_buttontop_line.setBackgroundColor(dividerColor);
        md_buttontop_line1.setBackgroundColor(dividerColor);
        md_buttontop_line2.setBackgroundColor(dividerColor);
        md_leftdiver_line.setBackgroundColor(dividerColor);
        md_rightdiver_line.setBackgroundColor(dividerColor);
        invalidate();
    }

    public void setButtonGravity(GravityEnum gravity) {
        buttonGravity = gravity;
        invertGravityIfNecessary();
    }

    int btnBgColor;

    public void setButtonBgColor(int btnBgColor) {
        this.btnBgColor = btnBgColor;
    }

    private void invertGravityIfNecessary() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return;
        }
        Configuration config = getResources().getConfiguration();
        if (config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
            switch (buttonGravity) {
                case START:
                    buttonGravity = GravityEnum.END;
                    break;
                case END:
                    buttonGravity = GravityEnum.START;
                    break;
            }
        }
    }

    public void setButtonStackedGravity(GravityEnum gravity) {
        for (DLButton mButton : buttons) {
            if (mButton != null) {
                mButton.setStackedGravity(gravity);
            }
        }
    }

    private void setUpDividersVisibility(@Nullable final View view, final boolean setForTop, final boolean setForBottom) {
        if (view == null) {
            return;
        }
        if (view instanceof ScrollView) {
            final ScrollView sv = (ScrollView) view;
            if (canScrollViewScroll(sv)) {
                addScrollListener(sv, setForTop, setForBottom);
            } else {
                if (setForTop) {
                    drawTopDivider = false;
                }
                if (setForBottom) {
                    drawBottomDivider = false;
                }
            }
        } else if (view instanceof AdapterView) {
            final AdapterView sv = (AdapterView) view;
            if (canAdapterViewScroll(sv)) {
                addScrollListener(sv, setForTop, setForBottom);
            } else {
                if (setForTop) {
                    drawTopDivider = false;
                }
                if (setForBottom) {
                    drawBottomDivider = false;
                }
            }
        } else if (view instanceof WebView) {
            view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    if (view.getMeasuredHeight() != 0) {
                        if (!canWebViewScroll((WebView) view)) {
                            if (setForTop) {
                                drawTopDivider = false;
                            }
                            if (setForBottom) {
                                drawBottomDivider = false;
                            }
                        } else {
                            addScrollListener((ViewGroup) view, setForTop, setForBottom);
                        }
                        view.getViewTreeObserver().removeOnPreDrawListener(this);
                    }
                    return true;
                }
            });
        } else if (view instanceof RecyclerView) {
            boolean canScroll = canRecyclerViewScroll((RecyclerView) view);
            if (setForTop) {
                drawTopDivider = canScroll;
            }
            if (setForBottom) {
                drawBottomDivider = canScroll;
            }
            if (canScroll) {
                addScrollListener((ViewGroup) view, setForTop, setForBottom);
            }
        } else if (view instanceof ViewGroup) {
            View topView = getTopView((ViewGroup) view);
            setUpDividersVisibility(topView, setForTop, setForBottom);
            View bottomView = getBottomView((ViewGroup) view);
            if (bottomView != topView) {
                setUpDividersVisibility(bottomView, false, true);
            }
        }
    }

    private void addScrollListener(final ViewGroup vg, final boolean setForTop, final boolean setForBottom) {
        if ((!setForBottom && topOnScrollChangedListener == null
                || (setForBottom && bottomOnScrollChangedListener == null))) {
            if (vg instanceof RecyclerView) {
                RecyclerView.OnScrollListener scrollListener =
                        new RecyclerView.OnScrollListener() {
                            @Override
                            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                                super.onScrolled(recyclerView, dx, dy);
                                boolean hasButtons = false;
                                for (DLButton button : buttons) {
                                    if (button != null && button.getVisibility() != View.GONE) {
                                        hasButtons = true;
                                        break;
                                    }
                                }
                                invalidateDividersForScrollingView(vg, setForTop, setForBottom, hasButtons);
                                invalidate();
                            }
                        };
                ((RecyclerView) vg).addOnScrollListener(scrollListener);
                scrollListener.onScrolled((RecyclerView) vg, 0, 0);
            } else {
                ViewTreeObserver.OnScrollChangedListener onScrollChangedListener =
                        new ViewTreeObserver.OnScrollChangedListener() {
                            @Override
                            public void onScrollChanged() {
                                boolean hasButtons = false;
                                for (DLButton button : buttons) {
                                    if (button != null && button.getVisibility() != View.GONE) {
                                        hasButtons = true;
                                        break;
                                    }
                                }
                                if (vg instanceof WebView) {
                                    invalidateDividersForWebView((WebView) vg, setForTop, setForBottom, hasButtons);
                                } else {
                                    invalidateDividersForScrollingView(vg, setForTop, setForBottom, hasButtons);
                                }
                                invalidate();
                            }
                        };
                if (!setForBottom) {
                    topOnScrollChangedListener = onScrollChangedListener;
                    vg.getViewTreeObserver().addOnScrollChangedListener(topOnScrollChangedListener);
                } else {
                    bottomOnScrollChangedListener = onScrollChangedListener;
                    vg.getViewTreeObserver().addOnScrollChangedListener(bottomOnScrollChangedListener);
                }
                onScrollChangedListener.onScrollChanged();
            }
        }
    }

    private void invalidateDividersForScrollingView(
            ViewGroup view, final boolean setForTop, boolean setForBottom, boolean hasButtons) {
        if (setForTop && view.getChildCount() > 0) {
            drawTopDivider = titleBar != null && titleBar.getVisibility() != View.GONE &&
                    // Not scrolled to the top.
                    view.getScrollY() + view.getPaddingTop() > view.getChildAt(0).getTop();
        }
        if (setForBottom && view.getChildCount() > 0) {
            drawBottomDivider = hasButtons && view.getScrollY() + view.getHeight() - view.getPaddingBottom() < view.getChildAt(view.getChildCount() - 1).getBottom();
        }
    }

    private void invalidateDividersForWebView(
            WebView view, final boolean setForTop, boolean setForBottom, boolean hasButtons) {
        if (setForTop) {
            drawTopDivider =
                    titleBar != null
                            && titleBar.getVisibility() != View.GONE
                            &&
                            // Not scrolled to the top.
                            view.getScrollY() + view.getPaddingTop() > 0;
        }
        if (setForBottom) {
            //noinspection deprecation
            drawBottomDivider =
                    hasButtons
                            && view.getScrollY() + view.getMeasuredHeight() - view.getPaddingBottom()
                            < view.getContentHeight() * view.getScale();
        }
    }
}
